
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author ntthinh
 */
public class DictionnaryImpl extends java.rmi.server.UnicastRemoteObject 
              implements Dictionnary {
    //les variables 

    public static final String FILE_ENTRY = "./entries.dat"; //le fichier etrée
    public static final String FILE_DEF = "./defs.dat";//stocke les définitions
    //list d'entité
    private static List<EntityImpl> listEntity = new ArrayList();
    private Entity entity;
    //la fonction de la contruction

    public DictionnaryImpl() throws java.rmi.RemoteException {
        super();
    }

    //retourner une entité correspondant avec ce term, si non retourner null
    private EntityImpl search(String term) {
        for (int i = 0; i < listEntity.size(); i++) {
            EntityImpl tmpEntity = (EntityImpl) listEntity.get(i);
            try {
                if (tmpEntity.myEntry().getTerm().equalsIgnoreCase(term)) {
                    return tmpEntity;
                }
            } catch (java.rmi.RemoteException e) {
                return null;
            }
        }
        return null;
    }

    /*
     *addEntity: ajouter un entité
     *
     * on doit ajouter les fonctions: setTerm (class WordImpl), setMyCategory(class WordImpl)
     * setDefinition (class EntityImpl) et setMyEntry(class WordImpl)
     */
    public void addEntity(String term, CategoryType categ, Property[] props, String def)
            throws TermExisted, java.rmi.RemoteException {
        EntityImpl tmpEntity = new EntityImpl();
        WordImpl tmpWord = new WordImpl();
        CategoryImpl tmpCategory = new CategoryImpl();//creer un categorie
        tmpCategory.setCategory(categ);//avec le type est CategoryType : categ
        //creer un mot avec les informations :  term, categories, proprietes
        tmpWord.setTerm(term);
        tmpWord.setMyCategory(tmpCategory);
        tmpWord.setMyProperties(props);
        //creer une entité et ajouter a la liste
        tmpEntity.setDefinition(def);
        tmpEntity.setMyEntry(tmpWord);
        listEntity.add(tmpEntity);

    }
    /*
     *delEntity : supprimer une entité dans ce dictionnaire
     */

    public void delEntity(String term)
            throws TermNotFound, java.rmi.RemoteException {
        //rechercher l'entite correspondant avec ce term
        EntityImpl tmpEntity = search(term);
        //si ne pas trouver -> jeter une exception
        if (tmpEntity == null) {
            throw new TermNotFound();
        } //si non supprimer cet entité
        else {
            this.listEntity.remove(tmpEntity);
        }
    }
    /*
     *modifDefinition : modifier la difinition d'un mot
     */

    public void modifDefinition(String term, String newdef)
            throws TermNotFound, java.rmi.RemoteException {
        //rechercher l'entite correspondant avec ce term
        EntityImpl tmpEntity = search(term);
        //si ne pas trouver -> jeter une exception
        if (tmpEntity == null) {
            throw new TermNotFound();
        } //si non, mettre a jour la nouvelle definition
        else {
            tmpEntity.setDefinition(newdef);
        }
    }

    public void sortDict(boolean direct) // ascendant (terme) si direct = TRUE, sinon descendant
            throws java.rmi.RemoteException {
    }
    /*
     *loadDict() : charger les donnes dans un fichier d'entrée à ce dictionnaire
     *
     */

    public long loadDict() //retourner la longueur de la liste
            throws DictFilesNotFound, java.rmi.RemoteException {

        try {
            String entry = null;
            String def = null;
            DataInputStream inEntry = new DataInputStream(new FileInputStream(FILE_ENTRY));
            DataInputStream inDef = new DataInputStream(new FileInputStream(FILE_DEF));
            //effacer les donnes
            listEntity.clear();
            while (true) {
                //dans le fichier entrée, chaque ligne stocke les proprietes d'une entité
                entry = inEntry.readLine();
                //dans le fichier definition, chaque ligne stocke une definition correspondante
                def = inDef.readLine();
                if (entry == null || def == null) {
                    return (long) listEntity.size();
                }

                EntityImpl tmpEntity = new EntityImpl();
                Word tmpWord = Util.getWord(entry);
                tmpEntity.setDefinition(Util.getDefinition(def));
                tmpEntity.setMyEntry(tmpWord);
                this.listEntity.add(tmpEntity);
            }


        } catch (IOException ex) {
            Logger.getLogger(DictionnaryImpl.class.getName()).log(Level.SEVERE, null, ex);
            throw new DictFilesNotFound();
        }

    }
    /*
     *sageDict() : sauvegarder ce dictionnaire
     */

    public void saveDict()
            throws java.rmi.RemoteException {
        //si il n'y a pas de mot
        if (listEntity.size() == 0) {
            return;
        }
        //si non, sauvegarder
        PrintWriter out_entry = null;
        PrintWriter out_def = null;
        try {
            out_entry = new PrintWriter(FILE_ENTRY);
            out_def = new PrintWriter(FILE_DEF);
            //ajouter les entités
            for (int i = 0; i < listEntity.size(); i++) {
                EntityImpl tmpEntity = (EntityImpl) listEntity.get(i);
                //sauvegarder le fichier de donnees
                String strEntity = "[" + i + "," + tmpEntity.myEntry().myCategory().toFile() + "," + tmpEntity.getEntry().toFile() + "]";
                out_entry.println(strEntity);
                //sauvegarder le fichier de la definition
                String strDef = i + ",« " + tmpEntity.myDefinition() + " »";
                out_def.println(strDef);
            }
            out_entry.flush();
            out_def.flush();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(DictionnaryImpl.class.getName()).log(Level.SEVERE, null, ex);
            out_entry.close();
        }

        out_entry.close();

    }

    public Entity findEntity(String term)
            throws TermNotFound, java.rmi.RemoteException {
        //rechercher l'entite correspondant avec ce term
        EntityImpl tmpEntity = search(term);
        //si ne pas trouver -> jeter une exception
        if (tmpEntity == null) {
            throw new TermNotFound();
        }
        //else
        this.entity = tmpEntity;
        return tmpEntity;
    }

    public Entity fistEntity()
            throws DictEmpty, java.rmi.RemoteException {
        //si il n'y a pas d'entite, retourner une exception
        if (listEntity.size() == 0) {
            throw new DictEmpty();
        }
        //en revanche, retourner la première entité
        return listEntity.get(0);
    }

    public Entity lastEntity()
            throws DictEmpty, java.rmi.RemoteException {
        //si il n'y a pas d'entite, retourner une exception
        if (listEntity.size() == 0) {
            throw new DictEmpty();
        }
        //en revanche, retourner la dernière entité
        return listEntity.get(listEntity.size() - 1);
    }

    public Entity nextEntity()
            throws DictEmpty, java.rmi.RemoteException {
        //si il n'y a pas d'entite, retourner une exception
        if (listEntity.size() == 0) {
            throw new DictEmpty();
        }
        //entite courante
        Entity currentEntity = this.entity;
        //index courant
        int currentIndex = -1;
        for (int i = 0; i < listEntity.size(); i++) {
            Entity tmp = (Entity) listEntity.get(i);
            if (tmp == currentEntity) {
                currentIndex = i;
            }
        }
        //si entité courante n'est pas la derniere entite
        if(currentIndex>=0&&currentIndex<(listEntity.size()-1))
        {
             currentEntity=listEntity.get(currentIndex+1);
            return currentEntity;
        }
        //par contre return la premiere entite
        return fistEntity();



    }

    public Entity prevEntity()
            throws DictEmpty, java.rmi.RemoteException {
         //si il n'y a pas d'entite, retourner une exception
        if (listEntity.size() == 0) {
            throw new DictEmpty();
        }
        //entite courante
        Entity currentEntity = this.entity;
        //index courant
        int currentIndex = -1;
        for (int i = 0; i < listEntity.size(); i++) {
            Entity tmp = (Entity) listEntity.get(i);
            if (tmp == currentEntity) {
                currentIndex = i;
            }
        }
        //si entité courante n'est pas la premiere entite
        if(currentIndex>0&&currentIndex<listEntity.size())
        {
             currentEntity=listEntity.get(currentIndex-1);
            return currentEntity;
        }
        //par contre return la derniere entite
        return lastEntity();
    }

    public long numEntities()
            throws java.rmi.RemoteException {
        return listEntity.size();
    }
}
